﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Data.Common;
using System.Diagnostics;

using Microsoft.Practices.Unity;

using ObjectEditor.Configuration;
using EQEmu.Database;
using EFTracingProvider;

namespace EQEmu.DatabasePlugin
{
    public static class TracingEQEmuContextExtensions
    {
        public static string FormattedCommand(CommandExecutionEventArgs e)
        {
            var q = e.Command;
            var cmdText = q.CommandText;

            string formatted = cmdText;
            foreach (dynamic p in q.Parameters)
            {
                var pname = p.ParameterName.ToString();                
                var value = p.Value.ToString();
                if (p.DbType == System.Data.DbType.String ||
                    p.DbType == System.Data.DbType.StringFixedLength)
                {
                    formatted = formatted.Replace("@" + pname, "'"+value+"'");
                }
                else
                {
                    formatted = formatted.Replace("@" + pname, value);
                }
            }

            formatted = formatted.Replace(Environment.NewLine, " ");
            return formatted + ";";
        }
    }

    public class TracingEQEmuContext : EQEmuContext
    {
        public TracingEQEmuContext(System.Data.EntityClient.EntityConnection con)
            : base(con)
        {
            this.EnableTracing();
        }
    }

    public class TracingEQEmuContextFactory : EQEmuContextFactory
    {
        private List<EFTracingConnection> _tracers = new List<EFTracingConnection>();

        public event EventHandler<CommandExecutionEventArgs> ContextCommandFinished;
        public event EventHandler<CommandExecutionEventArgs> ContextCommandExecuting;
        public event EventHandler<CommandExecutionEventArgs> ContextCommandFailed;

        protected override EQEmuContext Create(string connStr)
        {
            var tracer = EFTracingProviderUtils.CreateTracedEntityConnection(connStr);
            var t = tracer.StoreConnection as EFTracingConnection;
            _tracers.Add(t);

            t.CommandExecuting += t_CommandExecuting;
            t.CommandFailed += t_CommandFailed;
            t.CommandFinished += t_CommandFinished;

            EQEmuContext context = new TracingEQEmuContext(tracer);

            return context;
        }

        void t_CommandFinished(object sender, CommandExecutionEventArgs e)
        {
            Debug.WriteLine("DBCommandFinished:" + TracingEQEmuContextExtensions.FormattedCommand(e));

            var ev = this.ContextCommandFinished;
            if (ev != null)
            {
                ev(sender, e);
            }
        }

        void t_CommandFailed(object sender, CommandExecutionEventArgs e)
        {
            Debug.WriteLine("DBCommandFailed:" + TracingEQEmuContextExtensions.FormattedCommand(e));

            var ev = this.ContextCommandFailed;
            if (ev != null)
            {
                ev(sender, e);
            }
        }

        void t_CommandExecuting(object sender, CommandExecutionEventArgs e)
        {
            Debug.WriteLine("DBCommandExecuting:" + TracingEQEmuContextExtensions.FormattedCommand(e));

            var ev = this.ContextCommandExecuting;
            if (ev != null)
            {
                ev(sender, e);
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            foreach (var tracer in _tracers)
            {
                tracer.CommandExecuting -= t_CommandExecuting;
                tracer.CommandFailed -= t_CommandFailed;
                tracer.CommandFinished -= t_CommandFinished;
            }

            _tracers.Clear();
        }
    }
}
